Summary of Analysis

In this analysis, we investigate the impact of removing specific cell types from the reference dataset and mapping/querying them using the modified reference. The main steps include:

Cell Type Removal: CD4, CD8, CD14, and NK cell types are systematically removed from the reference dataset.

Mapping and Querying: Utilizing the modified reference, we map the query dataset.

Principal Component Regression: Regression of principal components (PCs) against predicted cell types is performed. We visualize PC scatter plots and box plots.

Distance Calculation: Calculation of Euclidean distances between the cell types in the reference and the corresponding cell types in the query.

Inter-Cell Type Distances: Computation of distances between the cell types removed from the reference and the cell types to which they were assigned in the query.

Introduction

Welcome to this document, where we delve into the results of a regression analysis involving Principal Components (PCs) and cell labels. Our exploration encompasses two distinct scenarios:

Regression of PCs against Observed Cell Labels in Query Dataset: This scenario involves the regression of Principal Components against the actual cell labels within the query dataset.

Regression of PCs against Predicted Cell Labels in Query Dataset: In this scenario, we perform regression of Principal Components against predicted cell labels in the query dataset. These predicted labels are derived from systematically excluding one cell at a time from the reference dataset. The modified reference is then employed to map the query dataset.

The analysis hinges on a Single-Cell RNA sequencing (scRNA-seq) 10x Genomics PBMC dataset. This dataset is divided into two subsets: the reference set (10x Single-Cell RNAseq PBMCs - Reference) and the query dataset (10x Single-Cell RNAseq PBMCs - Withheld Test Set). The dataset can be accessed from the following link: https://figshare.com/projects/Curated_10X_Data/137892

library(SingleR)
library(scater)
library(Polychrome)
library(plotly)
library(ggplot2)

Data Processing

In this section, we load the reference and withheld datasets, log-transform the data, and explore the impact of removing different cell types from the reference dataset on prediction accuracy.

PCA of reference

Analysis - Removing Cell Types

Here, we analyze the effect of removing individual cell types from the reference dataset on prediction accuracy using the SingleR package. We have a reference dataset containing CD4, CD8, CD14, and NK cell types. We remove CD4 cells from the reference and map query using this reference. Similarly, this process is performed for CD8, CD14, and NK cells individually, each time removing one cell type and mapping query with this modified reference.

# Removal of one cell type at a time from reference
tab <- lapply(unique(reference$label), function(i) {
  indx <- which(reference$label == i)
  refn <- reference[, -indx]
  annotations <- SingleR(query, ref = refn, labels = refn$label)
  table_result <- as.data.frame(table(annotations$labels, query$label))
  return(list(annotations = annotations, table_result = table_result))
})

df <- mapply(function(tbl_result, label) {
  indx <- which(tbl_result$Var2 == label)
  tbl_result[indx, ]
}, lapply(tab, `[[`, "table_result"), unique(reference$label), SIMPLIFY = FALSE)

df = do.call(rbind, df)
df <- subset(df, Freq > 0)

# Concordance plot
df$Var2 <- factor(df$Var2, levels = c("CD8", "NK", "CD4", "CD14"))
ggplot(df, aes(x = Var1, y = Var2, size = Freq)) + 
  geom_point() + 
  xlab("Predicted labels") + 
  ylab("Removed labels") + 
  theme_bw() + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

The scatter plot above displays removed cell types from reference on y axis and predicted cell type on x axis. For instance, if from reference dataset CD8 cells are removed, It will be predicted as CD4 cells in a query dataset.

PCA and Regression analysis

In this section, we apply PCA to the query dataset and perform regression analysis to understand the relationship between principal components and observed cell labels from query dataset.

query <- runPCA(query)

# Function to regress PCs against cell labels
regress_PCs <- function(data) {
  
  # Calculate R-squared values
  lm_models <- lapply(1:10, function(i) {
    lm_model <- lm(paste0("PC", i, " ~ CellTypes"), data = data)
    return(lm_model)
  })
  
  # Calculate R-squared values
  rsquared <- sapply(lm_models, function(model) {
    rsq <- summary(model)$r.squared
    return(rsq)
  })
  
  rsquared_df <- data.frame(PC = 1:10, R2 = rsquared)
  return(rsquared_df)
}

# Function to create scatter plot and convert to plotly
scatter_to_plotly <- function(data, x_col, y_col, color_col, title) {
  p <- ggplot(data, aes_string(x = x_col, y = y_col, color = color_col)) +
    geom_point(size = 0.5) +
    scale_color_manual(values = color_palette, guide = guide_legend(override.aes = list(size = 2))) +
    labs(x = x_col, y = y_col, title = title) +
    theme_bw()
  
  return(ggplotly(p))
}

calculatePairwiseDistancesAndPlotDensity <- function(query_data, ref_data, query_cell_type_col, ref_cell_type_col, cell_type_query, cell_type_reference,distance_metric, correlation_method = "pearson") {
  # Subset query and reference data to the specified cell type
  query_data_subset <- query_data[, !is.na(query_data[[query_cell_type_col]]) & query_data[[query_cell_type_col]] == cell_type_query]
  ref_data_subset <- ref_data[, !is.na(ref_data[[ref_cell_type_col]]) & ref_data[[ref_cell_type_col]] == cell_type_reference]
  
  # Convert to matrix
  query_mat <- t(as.matrix(assay(query_data_subset, "logcounts")))
  ref_mat <- t(as.matrix(assay(ref_data_subset, "logcounts")))
  
  # Combine query and reference matrices
  combined_mat <- rbind(query_mat, ref_mat)
  
  # Calculate pairwise distances or correlations for all comparisons
  if (distance_metric == "correlation") {
    if (correlation_method == "pearson") {
      dist_matrix <- cor(t(combined_mat), method = "pearson")
    } else if (correlation_method == "spearman") {
      dist_matrix <- cor(t(combined_mat), method = "spearman")
    } else {
      stop("Invalid correlation method. Available options: 'pearson', 'spearman'")
    }
  } else {
    dist_matrix <- dist(combined_mat, method = distance_metric)
  }
  
  # Convert dist_matrix to a square matrix
  dist_matrix <- as.matrix(dist_matrix)
  
  # Extract the distances or correlations for the different pairwise comparisons
  num_query_cells <- nrow(query_mat)
  num_ref_cells <- nrow(ref_mat)
  dist_query_query <- dist_matrix[1:num_query_cells, 1:num_query_cells]
  dist_ref_ref <- dist_matrix[(num_query_cells+1):(num_query_cells+num_ref_cells), (num_query_cells+1):(num_query_cells+num_ref_cells)]
  dist_query_ref <- dist_matrix[1:num_query_cells, (num_query_cells+1):(num_query_cells+num_ref_cells)]
  
  # Create data frame for plotting
  dist_df <- data.frame(
    Comparison = c(rep("Query vs Query", length(dist_query_query)),
                   rep("Reference vs Reference", length(dist_ref_ref)),
                   rep("Query vs Reference", length(dist_query_ref))),
    Distance = c(as.vector(dist_query_query),
                 as.vector(dist_ref_ref),
                 as.vector(dist_query_ref))
  )
  
  # Plot density plots
  ggplot(dist_df, aes(x = Distance, color = Comparison)) +
    geom_density() +
    labs(x = ifelse(distance_metric == "correlation", paste(correlation_method, "correlation"), "Distance"), y = "Density", title = "Pairwise Distance Analysis and Density Visualization") +
    theme_bw()
}

Visualizing Regression Results

Note: Here original/observed query data cell labels are used.

We visualize the outcome of the regression analysis by creating line plots that depict the R-squared values for each principal component.

PC1: The high R-squared value indicates that a significant portion of the variability in PC1 is explained by the cell labels. This suggests that PC1 captures meaningful differences between the cell types.

PC2: Captures a substantial amount of variation related to cell labels. This component contributes significantly to distinguishing between different cell types.

PC3: The R-squared value of PC3 indicates that it still captures a moderate amount of variation explained by cell labels, although it is less influential than PC1 and PC2.

PC4 to PC10: The R-squared values for PC4 to PC10 are relatively lower, ranging from 0.0366 to 0.0073. These components capture much less of the variation explained by the cell labels. Their low R-squared values might suggest that these principal components might be influenced by other factors not accounted for by the provided cell labels

# Data preparation
query_observed <- data.frame(reducedDim(query, "PCA"), CellTypes = query$label)
rsquared_df <- regress_PCs(query_observed)

# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
  geom_line() +
  geom_point(shape = 16) +
  labs(x = "Principal Component (PC)",
       y = "R-squared",
       title = "R-squared for Principal Components") +
  ylim(0, 1) +
  theme_bw() + 
  scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (Observed query dataset)

# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query_observed$CellType)), seeds)
names(color_palette) <- unique(query_observed$CellType)

PC1 vs PC2 scatter plot

The scatter plot of PC1 vs PC2 indicates that there are separate clusters for NK cells and CD14 cells, which means that these two cell types are well-separated from the others in this two-dimensional space defined by PC1 and PC2. This separation suggests that PC1 and PC2 capture distinct variations that allow for distinguishing between NK cells and CD14 cells from other cell types.

scatter_to_plotly(query_observed, "PC1", "PC2", "CellTypes", "PC1 vs PC2")

PC1 vs PC3 scatter plot

The variation captured by PC3 contributes to the separation of CD14 cells from other cell types when looking at the plot with PC3.

scatter_to_plotly(query_observed, "PC3", "PC1", "CellTypes", "PC1 vs PC3")

PC1 vs PC4 scatter plot

Similar to above results, the variation captured by PC4 contributes to the separation of CD14 cells from other cell types.

scatter_to_plotly(query_observed, "PC4", "PC1", "CellTypes", "PC1 vs PC4")

PC4 vs PC5 scatter plot

Plot of PC4 vs PC5 shows a mixed pattern with no clear separation or clustering of cell types, suggesting that the variation captured by these PCs may not have a strong discriminatory effect on the different cell types in the dataset.

scatter_to_plotly(query_observed, "PC4", "PC5", "CellTypes", "PC4 vs PC5")

Boxplots of PC1 vs Cell types

CD14 cells might exhibit distinct molecular characteristics that set them apart from the other three cell types.

ggplot(query_observed, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types

These results indicate that NK cells might exhibit distinct gene expression patterns or molecular characteristics captured by PC2.

ggplot(query_observed, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types

ggplot(query_observed, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD4 cell type is removed from reference dataset

In this section, we focus on the query dataset that was generated after removing CD4 cell types from the reference dataset. We perform analysis on this modified dataset to explore how the Principal Components (PCs) relate to the predicted cell labels.

PC1 captures a high amount of variance, suggesting that it explains a substantial portion of the variability in the data.

PC2 also captures a significant amount of variance, indicating its importance in explaining variability.

The R-squared values for PC3 to PC10 are much lower, indicating that these components capture relatively less variance in the data.

# Data preparation
query1 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[1]]$annotations$labels)
rsquared_df <- regress_PCs(query1)

# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
  geom_line() +
  geom_point(shape = 16) +
  labs(x = "Principal Component (PC)",
       y = "R-squared",
       title = "R-squared for Principal Components (CD4 cells removed from reference dataset)") +
  ylim(0, 1) +
  theme_bw() + 
  scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from reference CD4 cells removed)

We create scatter plots to visualize the PCA results for the query dataset with CD4 cell types removed from the reference.

# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query1$CellType)), seeds)
names(color_palette) <- unique(query1$CellType)

PC1 vs PC2 scatter plot

The scatter plot of PC1 vs PC2 for the query dataset with CD4 cell types removed from the reference demonstrates a distinct separation of clusters. This separation suggests that the variations captured by PC1 and PC2 are effective at distinguishing different cell types in the query dataset.

scatter_to_plotly(query1, "PC1", "PC2", "CellTypes", "PC1 vs PC2")

PC1 vs PC3 scatter plot

The separation of CD14 cells from the others along the PC3 axis is notable, indicating that the variation captured by PC3 contributes significantly to distinguishing CD14 cells from the rest. Additionally, the proximity of CD8 and NK cells along the PC3 axis suggests that these cell types may share some common gene expression patterns or molecular characteristics captured by PC3.

Also, concordance plot above revealed that when CD8 cells were removed from the reference dataset, a small subset of cells in the query dataset were being assigned as NK cells.

scatter_to_plotly(query1, "PC3", "PC1", "CellTypes", "PC1 vs PC3")

PC2 vs PC3 scatter plot

Separation of NK cells from other cell types seems to be influenced by both PC2 and PC3,

scatter_to_plotly(query1, "PC3", "PC2", "CellTypes", "PC3 vs PC2")

Boxplots of PC1 vs Cell types

ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types

ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types

ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD14 cell type is removed from reference dataset

In this section, we focus on the query dataset that was generated after removing CD14 cell types from the reference dataset. We perform analysis on this modified dataset to explore how the Principal Components (PCs) derived from PCA relate to the predicted cell labels.

PC1 explains approximately 11.06% of the total variance in the data. This value suggests that PC1 captures a moderate amount of variation in the dataset. While not extremely high, it still contributes significantly to the understanding of the differences among the data points.

PC2 explains approximately 86.10% of the total variance in the data. This high R-squared value indicates that PC2 captures a substantial amount of variation in the dataset. PC2 is a dominant component in explaining the differences among the data points.

PC3 explains approximately 44.17% of the total variance in the data. This value indicates that PC3 captures a moderate to high amount of variation in the dataset.

PC4 to PC10 each explain less than 10% of the total variance in the data. These components contribute relatively little to the overall variance and might capture noise or less significant patterns in the dataset.

# Data preparation
query2 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[2]]$annotations$labels)
rsquared_df <- regress_PCs(query2)

# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
  geom_line() +
  geom_point(shape = 16) +
  labs(x = "Principal Component (PC)",
       y = "R-squared",
       title = "R-squared for Principal Components (CD14 cells removed from reference dataset)") +
  ylim(0, 1) +
  theme_bw() + 
  scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from reference CD14 cells removed)

We create scatter plots to visualize the PCA results for the query dataset with CD14 cell types removed from the reference.

# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query2$CellType)), seeds)
names(color_palette) <- unique(query2$CellType)

PC1 vs PC2 scatter plot

In the scatter plot of PC1 vs PC2 for the query dataset (with reference CD14 cells removed), the following observations can be made:

Two Populations/Clusters of CD8 Cells: There are two distinct clusters or populations of CD8 cells visible on the plot. One of these clusters overlaps with CD4 cells, indicating some degree of similarity in their gene expression patterns.

NK cells are well-separated from the other cell types, suggesting that the variation captured by PC1 and PC2 is effective in distinguishing NK cells from the rest.

scatter_to_plotly(query2, "PC1", "PC2", "CellTypes", "PC1 vs PC2")

PC1 vs PC4 scatter plot

scatter_to_plotly(query2, "PC4", "PC1", "CellTypes", "PC1 vs PC4")

PC2 vs PC4 scatter plot

scatter_to_plotly(query2, "PC4", "PC2", "CellTypes", "PC4 vs PC2")

Boxplots of PC1 vs Cell types

The boxplots of PC1 values for different cell types reveal that the CD8 population exhibits a larger spread or variability along the PC1 axis compared to the CD4 and NK populations. This suggests that there might be greater heterogeneity or diversity within the CD8 cell population in terms of the gene expression patterns captured by PC1. On the other hand, the CD4 and NK populations seem to be more tightly clustered or have less variation along PC1.

ggplot(query2, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types

PC2 contributes to the separation of NK cells from the other two cell types.

ggplot(query2, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD8 cell type is removed from reference dataset

In this section, we focus on the query dataset that was generated after removing CD8 cell types from the reference dataset. We perform analysis on this modified dataset to explore how the Principal Components (PCs) derived from PCA relate to the predicted cell labels.

From the plot, we can see that PC1 and PC2 capture the majority of the variance in the data, with PC1 explaining the most variance. The subsequent PCs (PC3 to PC10) capture less variance and may represent smaller or more subtle patterns in the data.

# Data preparation
query3 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[3]]$annotations$labels)
rsquared_df <- regress_PCs(query3)

# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
  geom_line() +
  geom_point(shape = 16) +
  labs(x = "Principal Component (PC)",
       y = "R-squared",
       title = "R-squared for Principal Components (CD8 cells removed from reference dataset)") +
  ylim(0, 1) +
  theme_bw() + 
  scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from reference CD8 cells removed)

We created scatter plots to visualize the PCA results for the query dataset with CD8 cell types removed from the reference.

# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query3$CellType)), seeds)
names(color_palette) <- unique(query3$CellType)

PC1 vs PC2 scatter plot

The scatter plot of PC1 against PC2 for the query dataset, with reference CD8 cells removed, shows clear separation between different cell types. This separation could indicate that the variability captured by PC1 and PC2 is significant enough to differentiate between the remaining cell types in your dataset.

scatter_to_plotly(query3, "PC1", "PC2", "CellTypes", "PC1 vs PC2")

PC1 vs PC3 scatter plot

CD14 cells are separated from the other cell types along the PC3 axis. This indicates that the variation captured by PC3 contributes significantly to the differences between CD14 cells and the rest.

scatter_to_plotly(query3, "PC3", "PC1", "CellTypes", "PC1 vs PC3")

PC2 vs PC3 scatter plot

scatter_to_plotly(query3, "PC3", "PC2", "CellTypes", "PC2 vs PC3")

Boxplots of PC1 vs Cell types

ggplot(query3, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types

ggplot(query3, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types

ggplot(query3, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when NK cell type is removed from reference dataset

In this section, we focus on the query dataset that was generated after removing NK cell types from the reference dataset. We perform analysis on this modified dataset to explore how the Principal Components (PCs) derived from PCA relate to the predicted cell labels.

PC1 has an R-squared value of 0.949, indicating that it captures a substantial amount of variation in the dataset. It suggests that PC1 explains a large portion of the total variability.

PC2 has an R-squared value of 0.185, which is significantly lower than PC1. This means that PC2 explains a smaller portion of the total variability compared to PC1.

PC3 has an R-squared value of 0.396, indicating that it captures a moderate amount of variation. It’s higher than PC2 but not as high as PC1.

PCs 4 to 10 have much lower R-squared values ranging from 0.024 to 0.001, suggesting that they explain relatively small amounts of variation in the dataset.

# Data preparation
query4 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[4]]$annotations$labels)
rsquared_df <- regress_PCs(query4)

# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
  geom_line() +
  geom_point(shape = 16) +
  labs(x = "Principal Component (PC)",
       y = "R-squared",
       title = "R-squared for Principal Components (NK cells removed from reference dataset)") +
  ylim(0, 1) +
  theme_bw() + 
  scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from reference NK cells removed)

We create scatter plots to visualize the PCA results for the query dataset with NK cell types removed from the reference.

# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query4$CellType)), seeds)
names(color_palette) <- unique(query4$CellType)

PC1 vs PC2 scatter plot

CD14 cells are well separated from the other cell types along the PC1 axis.

There are two distinct populations of CD8 cells: one population is somewhat separate from the other, and the latter population has some overlap with CD4 cells.

scatter_to_plotly(query4, "PC1", "PC2", "CellTypes", "PC1 vs PC2")

PC1 vs PC3 scatter plot

CD14 cells continue to show a clear separation from the other cell types, indicating distinct differences in gene expression patterns or other molecular characteristics.

scatter_to_plotly(query4, "PC3", "PC1", "CellTypes", "PC1 vs PC3")

PC1 vs PC4 scatter plot

scatter_to_plotly(query4, "PC4", "PC1", "CellTypes", "PC1 vs PC4")

PC2 vs PC3 scatter plot

scatter_to_plotly(query4, "PC3", "PC2", "CellTypes", "PC3 vs PC2")

PC3 vs PC4 scatter plot

scatter_to_plotly(query4, "PC3", "PC4", "CellTypes", "PC3 vs PC4")

Boxplots of PC1 vs Cell types

PC1 captures significant variation that distinguishes CD14 cells from CD4 and CD8 cells.

ggplot(query4, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types

The following analysis reveals:

CD8 Cell Population Spread: The noticeable spread in the CD8 cell population along PC2 indicates that there is significant variability in the gene expression or molecular characteristics of CD8 cells that is captured by this principal component. This spread might suggest that there are subgroups or subtypes within the CD8 cell population that exhibit distinct patterns along PC2.

Two CD8 Cell Populations: The presence of two distinct CD8 cell populations in the PC1 vs PC2 scatter plot aligns with the spread seen in the boxplots of PC2 vs Cell types. This suggests that the variation captured by PC2 contributes to the differentiation between these two CD8 cell populations. The spread seen in the boxplots might be attributed to the differences between these populations in terms of the captured variation along PC2.

ggplot(query4, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types

ggplot(query4, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
    geom_boxplot() +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    guides(fill = "none") +
    xlab("CellTypes") +
    ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Distance analysis between distinct cell types of reference and query dataset

Note: Distances are being calculated for cell types in original/observed reference and query dataset.

Identified marker genes using trainSingleR() function from SingleR package and used these genes to compute distances between cells in reference and query dataset.

Distance between CD4 cells in reference and query

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD4", "CD4", "euclidean")

Distance between CD14 cells in reference and query

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD14", "CD14", "euclidean")

Distance between CD8 cells in reference and query

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD8", "CD8", "euclidean")

Distance between NK cells in reference and query

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "NK", "NK", "euclidean")

Distance analysis between cell types removed from reference and assigned cell type in query dataset

In this section, we calculate Euclidean distances between the removed cell types in the reference and their assigned cell types in the query.

# Extract labels from each element in the 'tab' list using lapply
label_lists <- lapply(tab, function(x) x$annotations$labels)
annotations <- do.call(data.frame, label_lists)
colnames(annotations) <- c("labels_CD4_removed", "labels_CD14_removed", "labels_CD8_removed", "labels_NK_removed")

Distance computation between CD4 cells in query and CD8 cells in reference

When, CD8 cells were removed from the reference and when this reference was used to annotate the query dataset, these cells were assigned as CD4 in query.

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD4_removed", "label", "CD8", "CD4", "euclidean")

Distance computation between CD8 cells in query and CD14 cells in reference

When, CD14 cells were removed from the reference and when this reference was used to annotate the query dataset, these cells were assigned as CD8 in query.

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD14_removed", "label", "CD8", "CD14", "euclidean")

Distance computation between CD4 cells in query and CD8 cells in reference

When, CD8 cells were removed from the reference and when this reference was used to annotate the query dataset, these cells were assigned as CD4 in query.

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD8_removed", "label", "CD4", "CD8", "euclidean")

Distance computation between CD8 cells in query and NK cells in reference

When, NK cells were removed from the reference and when this reference was used to annotate the query dataset, these cells were assigned as CD8 in query.

calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_NK_removed", "label", "CD8", "NK", "euclidean")

Principal Component Analysis (PCA) Key Observations:

CD4 and CD8 Overlap in PC1 vs PC2 in the Query: The overlap observed between CD4 and CD8 cells in the PC1 vs PC2 plot of the query dataset suggests the presence of shared gene expression patterns between these two cell types. This shared pattern might lead to their proximity in the PCA space.

CD14, CD8, and NK Separation in PC1 vs PC2 After CD4 Removal: Upon removing CD4 cells from the reference dataset, there is an improved separation of CD14, CD8, and NK cells in the PC1 vs PC2 plot. This enhancement in separation could be attributed to the reduction of noise caused by CD4 cells, enabling a clearer distinction between these cell populations.

Two CD8 Populations in PC2 vs PC3 After CD4 Removal: The absence of CD4 cells from the reference dataset has uncovered previously masked heterogeneity within CD8 cells. This is evident from the emergence of two distinct CD8 subpopulations in the PC2 vs PC3 plot, indicating that CD4 cells were influencing the grouping of CD8 cells.

Two CD8 Populations in PC1 vs PC2 After CD14 Removal: Following the removal of CD14, there are notable changes in the variance captured by PC1 and PC2. This unmasking of variability has led to the identification of two distinct CD8 subpopulations in the PC1 vs PC2 plot, suggesting that CD14 cells were masking this heterogeneity.

Two CD4 Populations in PC2 vs PC3 After CD8 Removal: The absence of CD8 T cells in the reference dataset has revealed hidden variability within CD4 T cells. This is evident from the appearance of two distinct CD4 subpopulations in the PC2 vs PC3 plot, highlighting that the presence of CD8 cells was impacting the representation of CD4 cells.

Two CD8 Populations in PC1 vs PC2 After NK Removal: Removing NK cells from the reference dataset has had an influence on the positioning of CD8 T cells in the PCA space. This effect is seen in the emergence of two CD8 cell populations in the PC1 vs PC2 plot, indicating that the presence of NK cells was affecting the distribution of CD8 cells.

Distinct CD4, CD14, and CD8 Populations in PC1 vs PC3 After NK Removal: The removal of NK cells from the reference dataset has brought about clearer separation between CD4 T cells, CD14, and CD8 cells in the PC1 vs PC3 plot. The masking effect of NK cells on the distinction between these populations has been alleviated.

Two CD8 Populations in PC2 vs PC3 After CD4 Removal: The absence of CD4 cells in the reference dataset has allowed for the identification of subtle heterogeneity within CD8 in the PC2 vs PC3 plot. This finding underscores how the presence of CD4 cells was impacting the representation of CD8 cell variability.

LS0tCnRpdGxlOiAiUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyBvbiBRdWVyeSBEYXRhc2V0IE1hcHBlZCBVc2luZyBSZWZlcmVuY2UsIHdpdGggT25lIENlbGwgVHlwZSBSZW1vdmVkIgpkYXRlOiAiMjAyMy0wNi0yMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogZGVmYXVsdAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogCiAgICAgICAgICAgIGNvbGxhcHNlZDogZmFsc2UKLS0tCiAgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBTdW1tYXJ5IG9mIEFuYWx5c2lzCgpJbiB0aGlzIGFuYWx5c2lzLCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgaW1wYWN0IG9mIHJlbW92aW5nIHNwZWNpZmljIGNlbGwgdHlwZXMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgYW5kIG1hcHBpbmcvcXVlcnlpbmcgdGhlbSB1c2luZyB0aGUgbW9kaWZpZWQgcmVmZXJlbmNlLiBUaGUgbWFpbiBzdGVwcyBpbmNsdWRlOgoKQ2VsbCBUeXBlIFJlbW92YWw6IENENCwgQ0Q4LCBDRDE0LCBhbmQgTksgY2VsbCB0eXBlcyBhcmUgc3lzdGVtYXRpY2FsbHkgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldC4KCk1hcHBpbmcgYW5kIFF1ZXJ5aW5nOiBVdGlsaXppbmcgdGhlIG1vZGlmaWVkIHJlZmVyZW5jZSwgd2UgbWFwIHRoZSBxdWVyeSBkYXRhc2V0LgoKUHJpbmNpcGFsIENvbXBvbmVudCBSZWdyZXNzaW9uOiBSZWdyZXNzaW9uIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIChQQ3MpIGFnYWluc3QgcHJlZGljdGVkIGNlbGwgdHlwZXMgaXMgcGVyZm9ybWVkLiBXZSB2aXN1YWxpemUgUEMgc2NhdHRlciBwbG90cyBhbmQgYm94IHBsb3RzLgoKRGlzdGFuY2UgQ2FsY3VsYXRpb246IENhbGN1bGF0aW9uIG9mIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgY2VsbCB0eXBlcyBpbiB0aGUgcmVmZXJlbmNlIGFuZCB0aGUgY29ycmVzcG9uZGluZyBjZWxsIHR5cGVzIGluIHRoZSBxdWVyeS4KCkludGVyLUNlbGwgVHlwZSBEaXN0YW5jZXM6IENvbXB1dGF0aW9uIG9mIGRpc3RhbmNlcyBiZXR3ZWVuIHRoZSBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB0aGUgY2VsbCB0eXBlcyB0byB3aGljaCB0aGV5IHdlcmUgYXNzaWduZWQgaW4gdGhlIHF1ZXJ5LgoKIyBJbnRyb2R1Y3Rpb24KCldlbGNvbWUgdG8gdGhpcyBkb2N1bWVudCwgd2hlcmUgd2UgZGVsdmUgaW50byB0aGUgcmVzdWx0cyBvZiBhIHJlZ3Jlc3Npb24gYW5hbHlzaXMgaW52b2x2aW5nIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ3MpIGFuZCBjZWxsIGxhYmVscy4gT3VyIGV4cGxvcmF0aW9uIGVuY29tcGFzc2VzIHR3byBkaXN0aW5jdCBzY2VuYXJpb3M6CgpSZWdyZXNzaW9uIG9mIFBDcyBhZ2FpbnN0IE9ic2VydmVkIENlbGwgTGFiZWxzIGluIFF1ZXJ5IERhdGFzZXQ6IFRoaXMgc2NlbmFyaW8gaW52b2x2ZXMgdGhlIHJlZ3Jlc3Npb24gb2YgUHJpbmNpcGFsIENvbXBvbmVudHMgYWdhaW5zdCB0aGUgYWN0dWFsIGNlbGwgbGFiZWxzIHdpdGhpbiB0aGUgcXVlcnkgZGF0YXNldC4KClJlZ3Jlc3Npb24gb2YgUENzIGFnYWluc3QgUHJlZGljdGVkIENlbGwgTGFiZWxzIGluIFF1ZXJ5IERhdGFzZXQ6IEluIHRoaXMgc2NlbmFyaW8sIHdlIHBlcmZvcm0gcmVncmVzc2lvbiBvZiBQcmluY2lwYWwgQ29tcG9uZW50cyBhZ2FpbnN0IHByZWRpY3RlZCBjZWxsIGxhYmVscyBpbiB0aGUgcXVlcnkgZGF0YXNldC4gVGhlc2UgcHJlZGljdGVkIGxhYmVscyBhcmUgZGVyaXZlZCBmcm9tIHN5c3RlbWF0aWNhbGx5IGV4Y2x1ZGluZyBvbmUgY2VsbCBhdCBhIHRpbWUgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQuIFRoZSBtb2RpZmllZCByZWZlcmVuY2UgaXMgdGhlbiBlbXBsb3llZCB0byBtYXAgdGhlIHF1ZXJ5IGRhdGFzZXQuCgpUaGUgYW5hbHlzaXMgaGluZ2VzIG9uIGEgU2luZ2xlLUNlbGwgUk5BIHNlcXVlbmNpbmcgKHNjUk5BLXNlcSkgMTB4IEdlbm9taWNzIFBCTUMgZGF0YXNldC4gVGhpcyBkYXRhc2V0IGlzIGRpdmlkZWQgaW50byB0d28gc3Vic2V0czogdGhlIHJlZmVyZW5jZSBzZXQgKDEweCBTaW5nbGUtQ2VsbCBSTkFzZXEgUEJNQ3MgLSBSZWZlcmVuY2UpIGFuZCB0aGUgcXVlcnkgZGF0YXNldCAoMTB4IFNpbmdsZS1DZWxsIFJOQXNlcSBQQk1DcyAtIFdpdGhoZWxkIFRlc3QgU2V0KS4gVGhlIGRhdGFzZXQgY2FuIGJlIGFjY2Vzc2VkIGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOiBodHRwczovL2ZpZ3NoYXJlLmNvbS9wcm9qZWN0cy9DdXJhdGVkXzEwWF9EYXRhLzEzNzg5MgoKCmBgYHtyIExpYnJhcmllcywgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KFNpbmdsZVIpCmxpYnJhcnkoc2NhdGVyKQpsaWJyYXJ5KFBvbHljaHJvbWUpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyBEYXRhIFByb2Nlc3NpbmcKCkluIHRoaXMgc2VjdGlvbiwgd2UgbG9hZCB0aGUgcmVmZXJlbmNlIGFuZCB3aXRoaGVsZCBkYXRhc2V0cywgbG9nLXRyYW5zZm9ybSB0aGUgZGF0YSwgYW5kIGV4cGxvcmUgdGhlIGltcGFjdCBvZiByZW1vdmluZyBkaWZmZXJlbnQgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldCBvbiBwcmVkaWN0aW9uIGFjY3VyYWN5LgoKYGBge3IgRGF0YSBwcm9jZXNzaW5nLCBlY2hvPUYsIHdhcm5pbmc9Rn0KIyBMb2FkIHJlZmVyZW5jZSBhbmQgd2l0aGhlbGQgZGF0YXNldHMKbG9hZCgifi9Eb3dubG9hZHMvMTB4X3BibWNzX3JlZmVyZW5jZV9zY2UucmRhIikKbG9hZCgifi9Eb3dubG9hZHMvMTB4X3BibWNzX3dpdGhoZWxkX3NjZS5yZGEiKQoKIyBMb2cgdHJhbnNmb3JtIGRhdGFzZXRzCnJlZmVyZW5jZSA8LSBsb2dOb3JtQ291bnRzKHBibWNzX3JlZmVyZW5jZV9zY2UpCnF1ZXJ5IDwtIGxvZ05vcm1Db3VudHMocGJtY3Nfd2l0aGhlbGRfc2NlKQpgYGAKCiMgUENBIG9mIHJlZmVyZW5jZQoKYGBge3IgUENBIHJlZmVyZW5jZSwgZWNobz1GLCB3YXJuaW5nPUZ9CiMjIFJ1biBQQ0EKcmVmZXJlbmNlIDwtIHJ1blBDQShyZWZlcmVuY2UpCmRmX3JlZiA8LSBkYXRhLmZyYW1lKHJlZHVjZWREaW0ocmVmZXJlbmNlLCAiUENBIiksIENlbGxUeXBlID0gcmVmZXJlbmNlJGxhYmVsKQoKIyBHZW5lcmF0ZSBjb2xvcnMKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbHMgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKGRmX3JlZiRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29scykgPC0gdW5pcXVlKGRmX3JlZiRDZWxsVHlwZSkKCiMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKcCA8LSBnZ3Bsb3QoZGZfcmVmLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBDZWxsVHlwZSkpICsKICAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMsIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkgKwogICAgIGxhYnMoeCA9ICJQQzEiLCB5ID0gIlBDMiIsIHRpdGxlID0gIlBDMSB2cyBQQzIgU2NhdHRlciBQbG90IikgKwogICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkocCkKYGBgCgojIEFuYWx5c2lzIC0gUmVtb3ZpbmcgQ2VsbCBUeXBlcwoKSGVyZSwgd2UgYW5hbHl6ZSB0aGUgZWZmZWN0IG9mIHJlbW92aW5nIGluZGl2aWR1YWwgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldCBvbiBwcmVkaWN0aW9uIGFjY3VyYWN5IHVzaW5nIHRoZSBTaW5nbGVSIHBhY2thZ2UuIFdlIGhhdmUgYSByZWZlcmVuY2UgZGF0YXNldCBjb250YWluaW5nIENENCwgQ0Q4LCBDRDE0LCBhbmQgTksgY2VsbCB0eXBlcy4gV2UgcmVtb3ZlIENENCBjZWxscyBmcm9tIHRoZSByZWZlcmVuY2UgYW5kIG1hcCBxdWVyeSB1c2luZyB0aGlzIHJlZmVyZW5jZS4gU2ltaWxhcmx5LCB0aGlzIHByb2Nlc3MgaXMgcGVyZm9ybWVkIGZvciBDRDgsIENEMTQsIGFuZCBOSyBjZWxscyBpbmRpdmlkdWFsbHksIGVhY2ggdGltZSByZW1vdmluZyBvbmUgY2VsbCB0eXBlIGFuZCBtYXBwaW5nIHF1ZXJ5IHdpdGggdGhpcyBtb2RpZmllZCByZWZlcmVuY2UuCgpgYGB7ciBBbmFseXNpcyAtIFJlbW92aW5nIENlbGwgVHlwZXMsIGVjaG89VCwgd2FybmluZz1GfQoKIyBSZW1vdmFsIG9mIG9uZSBjZWxsIHR5cGUgYXQgYSB0aW1lIGZyb20gcmVmZXJlbmNlCnRhYiA8LSBsYXBwbHkodW5pcXVlKHJlZmVyZW5jZSRsYWJlbCksIGZ1bmN0aW9uKGkpIHsKICBpbmR4IDwtIHdoaWNoKHJlZmVyZW5jZSRsYWJlbCA9PSBpKQogIHJlZm4gPC0gcmVmZXJlbmNlWywgLWluZHhdCiAgYW5ub3RhdGlvbnMgPC0gU2luZ2xlUihxdWVyeSwgcmVmID0gcmVmbiwgbGFiZWxzID0gcmVmbiRsYWJlbCkKICB0YWJsZV9yZXN1bHQgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbm5vdGF0aW9ucyRsYWJlbHMsIHF1ZXJ5JGxhYmVsKSkKICByZXR1cm4obGlzdChhbm5vdGF0aW9ucyA9IGFubm90YXRpb25zLCB0YWJsZV9yZXN1bHQgPSB0YWJsZV9yZXN1bHQpKQp9KQoKZGYgPC0gbWFwcGx5KGZ1bmN0aW9uKHRibF9yZXN1bHQsIGxhYmVsKSB7CiAgaW5keCA8LSB3aGljaCh0YmxfcmVzdWx0JFZhcjIgPT0gbGFiZWwpCiAgdGJsX3Jlc3VsdFtpbmR4LCBdCn0sIGxhcHBseSh0YWIsIGBbW2AsICJ0YWJsZV9yZXN1bHQiKSwgdW5pcXVlKHJlZmVyZW5jZSRsYWJlbCksIFNJTVBMSUZZID0gRkFMU0UpCgpkZiA9IGRvLmNhbGwocmJpbmQsIGRmKQpkZiA8LSBzdWJzZXQoZGYsIEZyZXEgPiAwKQoKIyBDb25jb3JkYW5jZSBwbG90CmRmJFZhcjIgPC0gZmFjdG9yKGRmJFZhcjIsIGxldmVscyA9IGMoIkNEOCIsICJOSyIsICJDRDQiLCAiQ0QxNCIpKQpnZ3Bsb3QoZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIHNpemUgPSBGcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICB4bGFiKCJQcmVkaWN0ZWQgbGFiZWxzIikgKyAKICB5bGFiKCJSZW1vdmVkIGxhYmVscyIpICsgCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKClRoZSBzY2F0dGVyIHBsb3QgYWJvdmUgZGlzcGxheXMgcmVtb3ZlZCBjZWxsIHR5cGVzIGZyb20gcmVmZXJlbmNlIG9uIHkgYXhpcyBhbmQgcHJlZGljdGVkIGNlbGwgdHlwZSBvbiB4IApheGlzLiBGb3IgaW5zdGFuY2UsIGlmIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQgQ0Q4IGNlbGxzIGFyZSByZW1vdmVkLCBJdCB3aWxsIGJlIHByZWRpY3RlZCBhcyBDRDQgY2VsbHMgaW4gYSBxdWVyeSBkYXRhc2V0LgoKIyBQQ0EgYW5kIFJlZ3Jlc3Npb24gYW5hbHlzaXMKCkluIHRoaXMgc2VjdGlvbiwgd2UgYXBwbHkgUENBIHRvIHRoZSBxdWVyeSBkYXRhc2V0IGFuZCBwZXJmb3JtIHJlZ3Jlc3Npb24gYW5hbHlzaXMgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJpbmNpcGFsIGNvbXBvbmVudHMgYW5kIG9ic2VydmVkIGNlbGwgbGFiZWxzIGZyb20gcXVlcnkgZGF0YXNldC4KCmBgYHtyIFJlZ3Jlc3Npb24gYW5hbHlzaXMsIGVjaG89VCwgd2FybmluZz1GfQpxdWVyeSA8LSBydW5QQ0EocXVlcnkpCgojIEZ1bmN0aW9uIHRvIHJlZ3Jlc3MgUENzIGFnYWluc3QgY2VsbCBsYWJlbHMKcmVncmVzc19QQ3MgPC0gZnVuY3Rpb24oZGF0YSkgewogIAogICMgQ2FsY3VsYXRlIFItc3F1YXJlZCB2YWx1ZXMKICBsbV9tb2RlbHMgPC0gbGFwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpIHsKICAgIGxtX21vZGVsIDwtIGxtKHBhc3RlMCgiUEMiLCBpLCAiIH4gQ2VsbFR5cGVzIiksIGRhdGEgPSBkYXRhKQogICAgcmV0dXJuKGxtX21vZGVsKQogIH0pCiAgCiAgIyBDYWxjdWxhdGUgUi1zcXVhcmVkIHZhbHVlcwogIHJzcXVhcmVkIDwtIHNhcHBseShsbV9tb2RlbHMsIGZ1bmN0aW9uKG1vZGVsKSB7CiAgICByc3EgPC0gc3VtbWFyeShtb2RlbCkkci5zcXVhcmVkCiAgICByZXR1cm4ocnNxKQogIH0pCiAgCiAgcnNxdWFyZWRfZGYgPC0gZGF0YS5mcmFtZShQQyA9IDE6MTAsIFIyID0gcnNxdWFyZWQpCiAgcmV0dXJuKHJzcXVhcmVkX2RmKQp9CgojIEZ1bmN0aW9uIHRvIGNyZWF0ZSBzY2F0dGVyIHBsb3QgYW5kIGNvbnZlcnQgdG8gcGxvdGx5CnNjYXR0ZXJfdG9fcGxvdGx5IDwtIGZ1bmN0aW9uKGRhdGEsIHhfY29sLCB5X2NvbCwgY29sb3JfY29sLCB0aXRsZSkgewogIHAgPC0gZ2dwbG90KGRhdGEsIGFlc19zdHJpbmcoeCA9IHhfY29sLCB5ID0geV9jb2wsIGNvbG9yID0gY29sb3JfY29sKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfcGFsZXR0ZSwgZ3VpZGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSArCiAgICBsYWJzKHggPSB4X2NvbCwgeSA9IHlfY29sLCB0aXRsZSA9IHRpdGxlKSArCiAgICB0aGVtZV9idygpCiAgCiAgcmV0dXJuKGdncGxvdGx5KHApKQp9CgpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5IDwtIGZ1bmN0aW9uKHF1ZXJ5X2RhdGEsIHJlZl9kYXRhLCBxdWVyeV9jZWxsX3R5cGVfY29sLCByZWZfY2VsbF90eXBlX2NvbCwgY2VsbF90eXBlX3F1ZXJ5LCBjZWxsX3R5cGVfcmVmZXJlbmNlLGRpc3RhbmNlX21ldHJpYywgY29ycmVsYXRpb25fbWV0aG9kID0gInBlYXJzb24iKSB7CiAgIyBTdWJzZXQgcXVlcnkgYW5kIHJlZmVyZW5jZSBkYXRhIHRvIHRoZSBzcGVjaWZpZWQgY2VsbCB0eXBlCiAgcXVlcnlfZGF0YV9zdWJzZXQgPC0gcXVlcnlfZGF0YVssICFpcy5uYShxdWVyeV9kYXRhW1txdWVyeV9jZWxsX3R5cGVfY29sXV0pICYgcXVlcnlfZGF0YVtbcXVlcnlfY2VsbF90eXBlX2NvbF1dID09IGNlbGxfdHlwZV9xdWVyeV0KICByZWZfZGF0YV9zdWJzZXQgPC0gcmVmX2RhdGFbLCAhaXMubmEocmVmX2RhdGFbW3JlZl9jZWxsX3R5cGVfY29sXV0pICYgcmVmX2RhdGFbW3JlZl9jZWxsX3R5cGVfY29sXV0gPT0gY2VsbF90eXBlX3JlZmVyZW5jZV0KICAKICAjIENvbnZlcnQgdG8gbWF0cml4CiAgcXVlcnlfbWF0IDwtIHQoYXMubWF0cml4KGFzc2F5KHF1ZXJ5X2RhdGFfc3Vic2V0LCAibG9nY291bnRzIikpKQogIHJlZl9tYXQgPC0gdChhcy5tYXRyaXgoYXNzYXkocmVmX2RhdGFfc3Vic2V0LCAibG9nY291bnRzIikpKQogIAogICMgQ29tYmluZSBxdWVyeSBhbmQgcmVmZXJlbmNlIG1hdHJpY2VzCiAgY29tYmluZWRfbWF0IDwtIHJiaW5kKHF1ZXJ5X21hdCwgcmVmX21hdCkKICAKICAjIENhbGN1bGF0ZSBwYWlyd2lzZSBkaXN0YW5jZXMgb3IgY29ycmVsYXRpb25zIGZvciBhbGwgY29tcGFyaXNvbnMKICBpZiAoZGlzdGFuY2VfbWV0cmljID09ICJjb3JyZWxhdGlvbiIpIHsKICAgIGlmIChjb3JyZWxhdGlvbl9tZXRob2QgPT0gInBlYXJzb24iKSB7CiAgICAgIGRpc3RfbWF0cml4IDwtIGNvcih0KGNvbWJpbmVkX21hdCksIG1ldGhvZCA9ICJwZWFyc29uIikKICAgIH0gZWxzZSBpZiAoY29ycmVsYXRpb25fbWV0aG9kID09ICJzcGVhcm1hbiIpIHsKICAgICAgZGlzdF9tYXRyaXggPC0gY29yKHQoY29tYmluZWRfbWF0KSwgbWV0aG9kID0gInNwZWFybWFuIikKICAgIH0gZWxzZSB7CiAgICAgIHN0b3AoIkludmFsaWQgY29ycmVsYXRpb24gbWV0aG9kLiBBdmFpbGFibGUgb3B0aW9uczogJ3BlYXJzb24nLCAnc3BlYXJtYW4nIikKICAgIH0KICB9IGVsc2UgewogICAgZGlzdF9tYXRyaXggPC0gZGlzdChjb21iaW5lZF9tYXQsIG1ldGhvZCA9IGRpc3RhbmNlX21ldHJpYykKICB9CiAgCiAgIyBDb252ZXJ0IGRpc3RfbWF0cml4IHRvIGEgc3F1YXJlIG1hdHJpeAogIGRpc3RfbWF0cml4IDwtIGFzLm1hdHJpeChkaXN0X21hdHJpeCkKICAKICAjIEV4dHJhY3QgdGhlIGRpc3RhbmNlcyBvciBjb3JyZWxhdGlvbnMgZm9yIHRoZSBkaWZmZXJlbnQgcGFpcndpc2UgY29tcGFyaXNvbnMKICBudW1fcXVlcnlfY2VsbHMgPC0gbnJvdyhxdWVyeV9tYXQpCiAgbnVtX3JlZl9jZWxscyA8LSBucm93KHJlZl9tYXQpCiAgZGlzdF9xdWVyeV9xdWVyeSA8LSBkaXN0X21hdHJpeFsxOm51bV9xdWVyeV9jZWxscywgMTpudW1fcXVlcnlfY2VsbHNdCiAgZGlzdF9yZWZfcmVmIDwtIGRpc3RfbWF0cml4WyhudW1fcXVlcnlfY2VsbHMrMSk6KG51bV9xdWVyeV9jZWxscytudW1fcmVmX2NlbGxzKSwgKG51bV9xdWVyeV9jZWxscysxKToobnVtX3F1ZXJ5X2NlbGxzK251bV9yZWZfY2VsbHMpXQogIGRpc3RfcXVlcnlfcmVmIDwtIGRpc3RfbWF0cml4WzE6bnVtX3F1ZXJ5X2NlbGxzLCAobnVtX3F1ZXJ5X2NlbGxzKzEpOihudW1fcXVlcnlfY2VsbHMrbnVtX3JlZl9jZWxscyldCiAgCiAgIyBDcmVhdGUgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKICBkaXN0X2RmIDwtIGRhdGEuZnJhbWUoCiAgICBDb21wYXJpc29uID0gYyhyZXAoIlF1ZXJ5IHZzIFF1ZXJ5IiwgbGVuZ3RoKGRpc3RfcXVlcnlfcXVlcnkpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiUmVmZXJlbmNlIHZzIFJlZmVyZW5jZSIsIGxlbmd0aChkaXN0X3JlZl9yZWYpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiUXVlcnkgdnMgUmVmZXJlbmNlIiwgbGVuZ3RoKGRpc3RfcXVlcnlfcmVmKSkpLAogICAgRGlzdGFuY2UgPSBjKGFzLnZlY3RvcihkaXN0X3F1ZXJ5X3F1ZXJ5KSwKICAgICAgICAgICAgICAgICBhcy52ZWN0b3IoZGlzdF9yZWZfcmVmKSwKICAgICAgICAgICAgICAgICBhcy52ZWN0b3IoZGlzdF9xdWVyeV9yZWYpKQogICkKICAKICAjIFBsb3QgZGVuc2l0eSBwbG90cwogIGdncGxvdChkaXN0X2RmLCBhZXMoeCA9IERpc3RhbmNlLCBjb2xvciA9IENvbXBhcmlzb24pKSArCiAgICBnZW9tX2RlbnNpdHkoKSArCiAgICBsYWJzKHggPSBpZmVsc2UoZGlzdGFuY2VfbWV0cmljID09ICJjb3JyZWxhdGlvbiIsIHBhc3RlKGNvcnJlbGF0aW9uX21ldGhvZCwgImNvcnJlbGF0aW9uIiksICJEaXN0YW5jZSIpLCB5ID0gIkRlbnNpdHkiLCB0aXRsZSA9ICJQYWlyd2lzZSBEaXN0YW5jZSBBbmFseXNpcyBhbmQgRGVuc2l0eSBWaXN1YWxpemF0aW9uIikgKwogICAgdGhlbWVfYncoKQp9CmBgYAoKIyBWaXN1YWxpemluZyBSZWdyZXNzaW9uIFJlc3VsdHMKCk5vdGU6IEhlcmUgb3JpZ2luYWwvb2JzZXJ2ZWQgcXVlcnkgZGF0YSBjZWxsIGxhYmVscyBhcmUgdXNlZC4KCldlIHZpc3VhbGl6ZSB0aGUgb3V0Y29tZSBvZiB0aGUgcmVncmVzc2lvbiBhbmFseXNpcyBieSBjcmVhdGluZyBsaW5lIHBsb3RzIHRoYXQgZGVwaWN0IHRoZSBSLXNxdWFyZWQgdmFsdWVzIGZvciBlYWNoIHByaW5jaXBhbCBjb21wb25lbnQuIAoKUEMxOiBUaGUgaGlnaCBSLXNxdWFyZWQgdmFsdWUgaW5kaWNhdGVzIHRoYXQgYSBzaWduaWZpY2FudCBwb3J0aW9uIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBQQzEgaXMgZXhwbGFpbmVkIGJ5IHRoZSBjZWxsIGxhYmVscy4gVGhpcyBzdWdnZXN0cyB0aGF0IFBDMSBjYXB0dXJlcyBtZWFuaW5nZnVsIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIGNlbGwgdHlwZXMuCgpQQzI6IENhcHR1cmVzIGEgc3Vic3RhbnRpYWwgYW1vdW50IG9mIHZhcmlhdGlvbiByZWxhdGVkIHRvIGNlbGwgbGFiZWxzLiBUaGlzIGNvbXBvbmVudCBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIGRpc3Rpbmd1aXNoaW5nIGJldHdlZW4gZGlmZmVyZW50IGNlbGwgdHlwZXMuCgpQQzM6IFRoZSBSLXNxdWFyZWQgdmFsdWUgb2YgUEMzIGluZGljYXRlcyB0aGF0IGl0IHN0aWxsIGNhcHR1cmVzIGEgbW9kZXJhdGUgYW1vdW50IG9mIHZhcmlhdGlvbiBleHBsYWluZWQgYnkgY2VsbCBsYWJlbHMsIGFsdGhvdWdoIGl0IGlzIGxlc3MgaW5mbHVlbnRpYWwgdGhhbiBQQzEgYW5kIFBDMi4KClBDNCB0byBQQzEwOiBUaGUgUi1zcXVhcmVkIHZhbHVlcyBmb3IgUEM0IHRvIFBDMTAgYXJlIHJlbGF0aXZlbHkgbG93ZXIsIHJhbmdpbmcgZnJvbSAwLjAzNjYgdG8gMC4wMDczLiBUaGVzZSBjb21wb25lbnRzIGNhcHR1cmUgbXVjaCBsZXNzIG9mIHRoZSB2YXJpYXRpb24gZXhwbGFpbmVkIGJ5IHRoZSBjZWxsIGxhYmVscy4gVGhlaXIgbG93IFItc3F1YXJlZCB2YWx1ZXMgbWlnaHQgc3VnZ2VzdCB0aGF0IHRoZXNlIHByaW5jaXBhbCBjb21wb25lbnRzIG1pZ2h0IGJlIGluZmx1ZW5jZWQgYnkgb3RoZXIgZmFjdG9ycyBub3QgYWNjb3VudGVkIGZvciBieSB0aGUgcHJvdmlkZWQgY2VsbCBsYWJlbHMKCmBgYHtyIFIyIGFuYWx5c2lzLCBlY2hvPVQsIHdhcm5pbmc9Rn0KIyBEYXRhIHByZXBhcmF0aW9uCnF1ZXJ5X29ic2VydmVkIDwtIGRhdGEuZnJhbWUocmVkdWNlZERpbShxdWVyeSwgIlBDQSIpLCBDZWxsVHlwZXMgPSBxdWVyeSRsYWJlbCkKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnlfb2JzZXJ2ZWQpCgojIENyZWF0ZSBhIGxpbmUgcGxvdCB1c2luZyBnZ3Bsb3QKZ2dwbG90KHJzcXVhcmVkX2RmLCBhZXMoeCA9IFBDLCB5ID0gUjIpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNikgKwogIGxhYnMoeCA9ICJQcmluY2lwYWwgQ29tcG9uZW50IChQQykiLAogICAgICAgeSA9ICJSLXNxdWFyZWQiLAogICAgICAgdGl0bGUgPSAiUi1zcXVhcmVkIGZvciBQcmluY2lwYWwgQ29tcG9uZW50cyIpICsKICB5bGltKDAsIDEpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTAsIGxhYmVscyA9IDE6MTApCmBgYAoKIyBTY2F0dGVyIHBsb3RzIGJldHdlZW4gZGlmZmVyZW50IFBDcyBmb3IgcXVlcnkgZGF0YXNldCAoT2JzZXJ2ZWQgcXVlcnkgZGF0YXNldCkKCmBgYHtyIHNjYXR0ZXIgcGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VCwgd2FybmluZz1GfQoKIyBEZWZpbmUgY29sb3IgcGFsZXR0ZQpzZWVkcyA8LSBjKCIjRkYwMDAwRkYiLCAiI0NDRkYwMEZGIiwgIiMwMEZGNjZGRiIsICIjMDA2NkZGRkYiLCAiI0NDMDBGRkZGIikKY29sb3JfcGFsZXR0ZSA8LSBjcmVhdGVQYWxldHRlKGxlbmd0aCh1bmlxdWUocXVlcnlfb2JzZXJ2ZWQkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeV9vYnNlcnZlZCRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKVGhlIHNjYXR0ZXIgcGxvdCBvZiBQQzEgdnMgUEMyIGluZGljYXRlcyB0aGF0IHRoZXJlIGFyZSBzZXBhcmF0ZSBjbHVzdGVycyBmb3IgTksgY2VsbHMgYW5kIENEMTQgY2VsbHMsIHdoaWNoIG1lYW5zIHRoYXQgdGhlc2UgdHdvIGNlbGwgdHlwZXMgYXJlIHdlbGwtc2VwYXJhdGVkIGZyb20gdGhlIG90aGVycyBpbiB0aGlzIHR3by1kaW1lbnNpb25hbCBzcGFjZSBkZWZpbmVkIGJ5IFBDMSBhbmQgUEMyLiBUaGlzIHNlcGFyYXRpb24gc3VnZ2VzdHMgdGhhdCBQQzEgYW5kIFBDMiBjYXB0dXJlIGRpc3RpbmN0IHZhcmlhdGlvbnMgdGhhdCBhbGxvdyBmb3IgZGlzdGluZ3Vpc2hpbmcgYmV0d2VlbiBOSyBjZWxscyBhbmQgQ0QxNCBjZWxscyBmcm9tIG90aGVyIGNlbGwgdHlwZXMuCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDMSB2cyBQQzIsIGVjaG89VCwgd2FybmluZz1GfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeV9vYnNlcnZlZCwgIlBDMSIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzIiKQpgYGAKCiMjIFBDMSB2cyBQQzMgc2NhdHRlciBwbG90CgpUaGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMyBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBDRDE0IGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcyB3aGVuIGxvb2tpbmcgYXQgdGhlIHBsb3Qgd2l0aCBQQzMuCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDMSB2cyBQQzMsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnlfb2JzZXJ2ZWQsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKU2ltaWxhciB0byBhYm92ZSByZXN1bHRzLCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDNCBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBDRDE0IGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcy4KCmBgYHtyIHNjYXR0ZXIgcGxvdHMgcXVlcnkgb2JzZXJ2ZWQgUEMxIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeV9vYnNlcnZlZCwgIlBDNCIsICJQQzEiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzQiKQpgYGAKCiMjIFBDNCB2cyBQQzUgc2NhdHRlciBwbG90CgpQbG90IG9mIFBDNCB2cyBQQzUgc2hvd3MgYSBtaXhlZCBwYXR0ZXJuIHdpdGggbm8gY2xlYXIgc2VwYXJhdGlvbiBvciBjbHVzdGVyaW5nIG9mIGNlbGwgdHlwZXMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IHRoZXNlIFBDcyBtYXkgbm90IGhhdmUgYSBzdHJvbmcgZGlzY3JpbWluYXRvcnkgZWZmZWN0IG9uIHRoZSBkaWZmZXJlbnQgY2VsbCB0eXBlcyBpbiB0aGUgZGF0YXNldC4gCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDNCB2cyBQQzUsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnlfb2JzZXJ2ZWQsICJQQzQiLCAiUEM1IiwgIkNlbGxUeXBlcyIsICJQQzQgdnMgUEM1IikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKQ0QxNCBjZWxscyBtaWdodCBleGhpYml0IGRpc3RpbmN0IG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MgdGhhdCBzZXQgdGhlbSBhcGFydCBmcm9tIHRoZSBvdGhlciB0aHJlZSBjZWxsIHR5cGVzLgoKYGBge3IgUEMxIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcwoKVGhlc2UgcmVzdWx0cyBpbmRpY2F0ZSB0aGF0IE5LIGNlbGxzIG1pZ2h0IGV4aGliaXQgZGlzdGluY3QgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIG9yIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MgY2FwdHVyZWQgYnkgUEMyLgoKYGBge3IgUEMyIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMiwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMiIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzMgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMzIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMywgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBDRDQgY2VsbCB0eXBlIGlzIHJlbW92ZWQgZnJvbSByZWZlcmVuY2UgZGF0YXNldAoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBmb2N1cyBvbiB0aGUgcXVlcnkgZGF0YXNldCB0aGF0IHdhcyBnZW5lcmF0ZWQgYWZ0ZXIgcmVtb3ZpbmcgQ0Q0IGNlbGwgdHlwZXMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQuIFdlIHBlcmZvcm0gYW5hbHlzaXMgb24gdGhpcyBtb2RpZmllZCBkYXRhc2V0IHRvIGV4cGxvcmUgaG93IHRoZSBQcmluY2lwYWwgQ29tcG9uZW50cyAoUENzKSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KIApQQzEgY2FwdHVyZXMgYSBoaWdoIGFtb3VudCBvZiB2YXJpYW5jZSwgc3VnZ2VzdGluZyB0aGF0IGl0IGV4cGxhaW5zIGEgc3Vic3RhbnRpYWwgcG9ydGlvbiBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuCgpQQzIgYWxzbyBjYXB0dXJlcyBhIHNpZ25pZmljYW50IGFtb3VudCBvZiB2YXJpYW5jZSwgaW5kaWNhdGluZyBpdHMgaW1wb3J0YW5jZSBpbiBleHBsYWluaW5nIHZhcmlhYmlsaXR5LgoKVGhlIFItc3F1YXJlZCB2YWx1ZXMgZm9yIFBDMyB0byBQQzEwIGFyZSBtdWNoIGxvd2VyLCBpbmRpY2F0aW5nIHRoYXQgdGhlc2UgY29tcG9uZW50cyBjYXB0dXJlIHJlbGF0aXZlbHkgbGVzcyB2YXJpYW5jZSBpbiB0aGUgZGF0YS4KCmBgYHtyIFIyIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTEgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbMV1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkxKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENENCBjZWxscyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQpIikgKwogIHlsaW0oMCwgMSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxMCwgbGFiZWxzID0gMToxMCkKYGBgCgojIFNjYXR0ZXIgcGxvdHMgYmV0d2VlbiBkaWZmZXJlbnQgUENzIGZvciBxdWVyeSBkYXRhc2V0IChmcm9tIHJlZmVyZW5jZSBDRDQgY2VsbHMgcmVtb3ZlZCkKCldlIGNyZWF0ZSBzY2F0dGVyIHBsb3RzIHRvIHZpc3VhbGl6ZSB0aGUgUENBIHJlc3VsdHMgZm9yIHRoZSBxdWVyeSBkYXRhc2V0IHdpdGggQ0Q0IGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGVmaW5lIGNvbG9yIHBhbGV0dGUKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbG9yX3BhbGV0dGUgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKHF1ZXJ5MSRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29sb3JfcGFsZXR0ZSkgPC0gdW5pcXVlKHF1ZXJ5MSRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKVGhlIHNjYXR0ZXIgcGxvdCBvZiBQQzEgdnMgUEMyIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIENENCBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGRlbW9uc3RyYXRlcyBhIGRpc3RpbmN0IHNlcGFyYXRpb24gb2YgY2x1c3RlcnMuIFRoaXMgc2VwYXJhdGlvbiBzdWdnZXN0cyB0aGF0IHRoZSB2YXJpYXRpb25zIGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGFyZSBlZmZlY3RpdmUgYXQgZGlzdGluZ3Vpc2hpbmcgZGlmZmVyZW50IGNlbGwgdHlwZXMgaW4gdGhlIHF1ZXJ5IGRhdGFzZXQuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzIsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkxLCAiUEMxIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDMiIpCmBgYAoKIyMgUEMxIHZzIFBDMyBzY2F0dGVyIHBsb3QKClRoZSBzZXBhcmF0aW9uIG9mIENEMTQgY2VsbHMgZnJvbSB0aGUgb3RoZXJzIGFsb25nIHRoZSBQQzMgYXhpcyBpcyBub3RhYmxlLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHZhcmlhdGlvbiBjYXB0dXJlZCBieSBQQzMgY29udHJpYnV0ZXMgc2lnbmlmaWNhbnRseSB0byBkaXN0aW5ndWlzaGluZyBDRDE0IGNlbGxzIGZyb20gdGhlIHJlc3QuIEFkZGl0aW9uYWxseSwgdGhlIHByb3hpbWl0eSBvZiBDRDggYW5kIE5LIGNlbGxzIGFsb25nIHRoZSBQQzMgYXhpcyBzdWdnZXN0cyB0aGF0IHRoZXNlIGNlbGwgdHlwZXMgbWF5IHNoYXJlIHNvbWUgY29tbW9uIGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBvciBtb2xlY3VsYXIgY2hhcmFjdGVyaXN0aWNzIGNhcHR1cmVkIGJ5IFBDMy4gCgpBbHNvLCBjb25jb3JkYW5jZSBwbG90IGFib3ZlIHJldmVhbGVkIHRoYXQgd2hlbiBDRDggY2VsbHMgd2VyZSByZW1vdmVkIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LCBhIHNtYWxsIHN1YnNldCBvZiBjZWxscyBpbiB0aGUgcXVlcnkgZGF0YXNldCB3ZXJlIGJlaW5nIGFzc2lnbmVkIGFzIE5LIGNlbGxzLgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q0IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzEgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5MSwgIlBDMyIsICJQQzEiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzMiKQpgYGAKCiMjIFBDMiB2cyBQQzMgc2NhdHRlciBwbG90CgpTZXBhcmF0aW9uIG9mIE5LIGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcyBzZWVtcyB0byBiZSBpbmZsdWVuY2VkIGJ5IGJvdGggUEMyIGFuZCBQQzMsCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMiB2cyBQQzMsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkxLCAiUEMzIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMzIHZzIFBDMiIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMxIHZzIENlbGwgdHlwZXMKCmBgYHtyIFBDMSB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MSwgZWNobz1UfQpnZ3Bsb3QocXVlcnkxLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMyIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkxLCBlY2hvPVR9CmdncGxvdChxdWVyeTEsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMyIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMyB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQMyB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MSwgZWNobz1UfQpnZ3Bsb3QocXVlcnkxLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBDRDE0IGNlbGwgdHlwZSBpcyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgZm9jdXMgb24gdGhlIHF1ZXJ5IGRhdGFzZXQgdGhhdCB3YXMgZ2VuZXJhdGVkIGFmdGVyIHJlbW92aW5nIENEMTQgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldC4gV2UgcGVyZm9ybSBhbmFseXNpcyBvbiB0aGlzIG1vZGlmaWVkIGRhdGFzZXQgdG8gZXhwbG9yZSBob3cgdGhlIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ3MpIGRlcml2ZWQgZnJvbSBQQ0EgcmVsYXRlIHRvIHRoZSBwcmVkaWN0ZWQgY2VsbCBsYWJlbHMuCgpQQzEgZXhwbGFpbnMgYXBwcm94aW1hdGVseSAxMS4wNiUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIHZhbHVlIHN1Z2dlc3RzIHRoYXQgUEMxIGNhcHR1cmVzIGEgbW9kZXJhdGUgYW1vdW50IG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldC4gV2hpbGUgbm90IGV4dHJlbWVseSBoaWdoLCBpdCBzdGlsbCBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIHRoZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBkaWZmZXJlbmNlcyBhbW9uZyB0aGUgZGF0YSBwb2ludHMuCgpQQzIgZXhwbGFpbnMgYXBwcm94aW1hdGVseSA4Ni4xMCUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIGhpZ2ggUi1zcXVhcmVkIHZhbHVlIGluZGljYXRlcyB0aGF0IFBDMiBjYXB0dXJlcyBhIHN1YnN0YW50aWFsIGFtb3VudCBvZiB2YXJpYXRpb24gaW4gdGhlIGRhdGFzZXQuIFBDMiBpcyBhIGRvbWluYW50IGNvbXBvbmVudCBpbiBleHBsYWluaW5nIHRoZSBkaWZmZXJlbmNlcyBhbW9uZyB0aGUgZGF0YSBwb2ludHMuCgpQQzMgZXhwbGFpbnMgYXBwcm94aW1hdGVseSA0NC4xNyUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIHZhbHVlIGluZGljYXRlcyB0aGF0IFBDMyBjYXB0dXJlcyBhIG1vZGVyYXRlIHRvIGhpZ2ggYW1vdW50IG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldC4KClBDNCB0byBQQzEwIGVhY2ggZXhwbGFpbiBsZXNzIHRoYW4gMTAlIG9mIHRoZSB0b3RhbCB2YXJpYW5jZSBpbiB0aGUgZGF0YS4KVGhlc2UgY29tcG9uZW50cyBjb250cmlidXRlIHJlbGF0aXZlbHkgbGl0dGxlIHRvIHRoZSBvdmVyYWxsIHZhcmlhbmNlIGFuZCBtaWdodCBjYXB0dXJlIG5vaXNlIG9yIGxlc3Mgc2lnbmlmaWNhbnQgcGF0dGVybnMgaW4gdGhlIGRhdGFzZXQuCgpgYGB7ciBSMiBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTIgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbMl1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkyKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENEMTQgY2VsbHMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBkYXRhc2V0KSIpICsKICB5bGltKDAsIDEpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTAsIGxhYmVscyA9IDE6MTApCmBgYAoKIyBTY2F0dGVyIHBsb3RzIGJldHdlZW4gZGlmZmVyZW50IFBDcyBmb3IgcXVlcnkgZGF0YXNldCAoZnJvbSByZWZlcmVuY2UgQ0QxNCBjZWxscyByZW1vdmVkKQoKV2UgY3JlYXRlIHNjYXR0ZXIgcGxvdHMgdG8gdmlzdWFsaXplIHRoZSBQQ0EgcmVzdWx0cyBmb3IgdGhlIHF1ZXJ5IGRhdGFzZXQgd2l0aCBDRDE0IGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDE0IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSwgZWNobz1UfQojIERlZmluZSBjb2xvciBwYWxldHRlCnNlZWRzIDwtIGMoIiNGRjAwMDBGRiIsICIjQ0NGRjAwRkYiLCAiIzAwRkY2NkZGIiwgIiMwMDY2RkZGRiIsICIjQ0MwMEZGRkYiKQpjb2xvcl9wYWxldHRlIDwtIGNyZWF0ZVBhbGV0dGUobGVuZ3RoKHVuaXF1ZShxdWVyeTIkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeTIkQ2VsbFR5cGUpCmBgYAoKIyMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKCkluIHRoZSBzY2F0dGVyIHBsb3Qgb2YgUEMxIHZzIFBDMiBmb3IgdGhlIHF1ZXJ5IGRhdGFzZXQgKHdpdGggcmVmZXJlbmNlIENEMTQgY2VsbHMgcmVtb3ZlZCksIHRoZSBmb2xsb3dpbmcgb2JzZXJ2YXRpb25zIGNhbiBiZSBtYWRlOgoKVHdvIFBvcHVsYXRpb25zL0NsdXN0ZXJzIG9mIENEOCBDZWxsczogVGhlcmUgYXJlIHR3byBkaXN0aW5jdCBjbHVzdGVycyBvciBwb3B1bGF0aW9ucyBvZiBDRDggY2VsbHMgdmlzaWJsZSBvbiB0aGUgcGxvdC4gT25lIG9mIHRoZXNlIGNsdXN0ZXJzIG92ZXJsYXBzIHdpdGggQ0Q0IGNlbGxzLCBpbmRpY2F0aW5nIHNvbWUgZGVncmVlIG9mIHNpbWlsYXJpdHkgaW4gdGhlaXIgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zLgoKTksgY2VsbHMgYXJlIHdlbGwtc2VwYXJhdGVkIGZyb20gdGhlIG90aGVyIGNlbGwgdHlwZXMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGlzIGVmZmVjdGl2ZSBpbiBkaXN0aW5ndWlzaGluZyBOSyBjZWxscyBmcm9tIHRoZSByZXN0LgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMiwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzEiLCAiUEMyIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMyIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzQiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEM0IikKYGBgCgojIyBQQzIgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMyIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzQiLCAiUEMyIiwgIkNlbGxUeXBlcyIsICJQQzQgdnMgUEMyIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKVGhlIGJveHBsb3RzIG9mIFBDMSB2YWx1ZXMgZm9yIGRpZmZlcmVudCBjZWxsIHR5cGVzIHJldmVhbCB0aGF0IHRoZSBDRDggcG9wdWxhdGlvbiBleGhpYml0cyBhIGxhcmdlciBzcHJlYWQgb3IgdmFyaWFiaWxpdHkgYWxvbmcgdGhlIFBDMSBheGlzIGNvbXBhcmVkIHRvIHRoZSBDRDQgYW5kIE5LIHBvcHVsYXRpb25zLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlcmUgbWlnaHQgYmUgZ3JlYXRlciBoZXRlcm9nZW5laXR5IG9yIGRpdmVyc2l0eSB3aXRoaW4gdGhlIENEOCBjZWxsIHBvcHVsYXRpb24gaW4gdGVybXMgb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBjYXB0dXJlZCBieSBQQzEuIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgQ0Q0IGFuZCBOSyBwb3B1bGF0aW9ucyBzZWVtIHRvIGJlIG1vcmUgdGlnaHRseSBjbHVzdGVyZWQgb3IgaGF2ZSBsZXNzIHZhcmlhdGlvbiBhbG9uZyBQQzEuCgpgYGB7ciBQQzEgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTIsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MiwgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzEsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzEiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMyIHZzIENlbGwgdHlwZXMKClBDMiBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBOSyBjZWxscyBmcm9tIHRoZSBvdGhlciB0d28gY2VsbCB0eXBlcy4KCmBgYHtyIFBDMiB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5IDIsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MiwgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzIsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyBRdWVyeSBkYXRhc2V0IHdoZW4gQ0Q4IGNlbGwgdHlwZSBpcyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgZm9jdXMgb24gdGhlIHF1ZXJ5IGRhdGFzZXQgdGhhdCB3YXMgZ2VuZXJhdGVkIGFmdGVyIHJlbW92aW5nIENEOCBjZWxsIHR5cGVzIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LiBXZSBwZXJmb3JtIGFuYWx5c2lzIG9uIHRoaXMgbW9kaWZpZWQgZGF0YXNldCB0byBleHBsb3JlIGhvdyB0aGUgUHJpbmNpcGFsIENvbXBvbmVudHMgKFBDcykgZGVyaXZlZCBmcm9tIFBDQSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KCkZyb20gdGhlIHBsb3QsIHdlIGNhbiBzZWUgdGhhdCBQQzEgYW5kIFBDMiBjYXB0dXJlIHRoZSBtYWpvcml0eSBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIGRhdGEsIHdpdGggUEMxIGV4cGxhaW5pbmcgdGhlIG1vc3QgdmFyaWFuY2UuIFRoZSBzdWJzZXF1ZW50IFBDcyAoUEMzIHRvIFBDMTApIGNhcHR1cmUgbGVzcyB2YXJpYW5jZSBhbmQgbWF5IHJlcHJlc2VudCBzbWFsbGVyIG9yIG1vcmUgc3VidGxlIHBhdHRlcm5zIGluIHRoZSBkYXRhLgoKYGBge3IgUjIgcXVlcnkgKENEOCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTMgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbM11dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkzKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENEOCBjZWxscyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQpIikgKwogIHlsaW0oMCwgMSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxMCwgbGFiZWxzID0gMToxMCkKYGBgCgojIFNjYXR0ZXIgcGxvdHMgYmV0d2VlbiBkaWZmZXJlbnQgUENzIGZvciBxdWVyeSBkYXRhc2V0IChmcm9tIHJlZmVyZW5jZSBDRDggY2VsbHMgcmVtb3ZlZCkKCldlIGNyZWF0ZWQgc2NhdHRlciBwbG90cyB0byB2aXN1YWxpemUgdGhlIFBDQSByZXN1bHRzIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIENEOCBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlLgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q4IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSwgZWNobz1UfQojIERlZmluZSBjb2xvciBwYWxldHRlCnNlZWRzIDwtIGMoIiNGRjAwMDBGRiIsICIjQ0NGRjAwRkYiLCAiIzAwRkY2NkZGIiwgIiMwMDY2RkZGRiIsICIjQ0MwMEZGRkYiKQpjb2xvcl9wYWxldHRlIDwtIGNyZWF0ZVBhbGV0dGUobGVuZ3RoKHVuaXF1ZShxdWVyeTMkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeTMkQ2VsbFR5cGUpCmBgYAoKIyMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKClRoZSBzY2F0dGVyIHBsb3Qgb2YgUEMxIGFnYWluc3QgUEMyIGZvciB0aGUgcXVlcnkgZGF0YXNldCwgd2l0aCByZWZlcmVuY2UgQ0Q4IGNlbGxzIHJlbW92ZWQsIHNob3dzIGNsZWFyIHNlcGFyYXRpb24gYmV0d2VlbiBkaWZmZXJlbnQgY2VsbCB0eXBlcy4gVGhpcyBzZXBhcmF0aW9uIGNvdWxkIGluZGljYXRlIHRoYXQgdGhlIHZhcmlhYmlsaXR5IGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGlzIHNpZ25pZmljYW50IGVub3VnaCB0byBkaWZmZXJlbnRpYXRlIGJldHdlZW4gdGhlIHJlbWFpbmluZyBjZWxsIHR5cGVzIGluIHlvdXIgZGF0YXNldC4gCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDggcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzIsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkzLCAiUEMxIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDMiIpCmBgYAoKIyMgUEMxIHZzIFBDMyBzY2F0dGVyIHBsb3QKCkNEMTQgY2VsbHMgYXJlIHNlcGFyYXRlZCBmcm9tIHRoZSBvdGhlciBjZWxsIHR5cGVzIGFsb25nIHRoZSBQQzMgYXhpcy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMyBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIENEMTQgY2VsbHMgYW5kIHRoZSByZXN0LiAKCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKENEOCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMywgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTMsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzIgdnMgUEMzIHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q4IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzIgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5MywgIlBDMyIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMiB2cyBQQzMiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMSB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQQzEgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTMsIGVjaG8gPVR9CmdncGxvdChxdWVyeTMsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMxIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMiB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQQzIgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTMsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MywgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzIsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMzIHZzIENlbGwgdHlwZXMKCmBgYHtyIFBDMyB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MywgZWNobz1UfQpnZ3Bsb3QocXVlcnkzLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMywgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBOSyBjZWxsIHR5cGUgaXMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBkYXRhc2V0CgpJbiB0aGlzIHNlY3Rpb24sIHdlIGZvY3VzIG9uIHRoZSBxdWVyeSBkYXRhc2V0IHRoYXQgd2FzIGdlbmVyYXRlZCBhZnRlciByZW1vdmluZyBOSyBjZWxsIHR5cGVzIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LiBXZSBwZXJmb3JtIGFuYWx5c2lzIG9uIHRoaXMgbW9kaWZpZWQgZGF0YXNldCB0byBleHBsb3JlIGhvdyB0aGUgUHJpbmNpcGFsIENvbXBvbmVudHMgKFBDcykgZGVyaXZlZCBmcm9tIFBDQSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KClBDMSBoYXMgYW4gUi1zcXVhcmVkIHZhbHVlIG9mIDAuOTQ5LCBpbmRpY2F0aW5nIHRoYXQgaXQgY2FwdHVyZXMgYSBzdWJzdGFudGlhbCBhbW91bnQgb2YgdmFyaWF0aW9uIGluIHRoZSBkYXRhc2V0LiBJdCBzdWdnZXN0cyB0aGF0IFBDMSBleHBsYWlucyBhIGxhcmdlIHBvcnRpb24gb2YgdGhlIHRvdGFsIHZhcmlhYmlsaXR5LgoKUEMyIGhhcyBhbiBSLXNxdWFyZWQgdmFsdWUgb2YgMC4xODUsIHdoaWNoIGlzIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBQQzEuIFRoaXMgbWVhbnMgdGhhdCBQQzIgZXhwbGFpbnMgYSBzbWFsbGVyIHBvcnRpb24gb2YgdGhlIHRvdGFsIHZhcmlhYmlsaXR5IGNvbXBhcmVkIHRvIFBDMS4KClBDMyBoYXMgYW4gUi1zcXVhcmVkIHZhbHVlIG9mIDAuMzk2LCBpbmRpY2F0aW5nIHRoYXQgaXQgY2FwdHVyZXMgYSBtb2RlcmF0ZSBhbW91bnQgb2YgdmFyaWF0aW9uLiBJdCdzIGhpZ2hlciB0aGFuIFBDMiBidXQgbm90IGFzIGhpZ2ggYXMgUEMxLgoKUENzIDQgdG8gMTAgaGF2ZSBtdWNoIGxvd2VyIFItc3F1YXJlZCB2YWx1ZXMgcmFuZ2luZyBmcm9tIDAuMDI0IHRvIDAuMDAxLCBzdWdnZXN0aW5nIHRoYXQgdGhleSBleHBsYWluIHJlbGF0aXZlbHkgc21hbGwgYW1vdW50cyBvZiB2YXJpYXRpb24gaW4gdGhlIGRhdGFzZXQuCgpgYGB7ciBSMiBxdWVyeSAoTksgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTQgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbNF1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnk0KQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKE5LIGNlbGxzIHJlbW92ZWQgZnJvbSByZWZlcmVuY2UgZGF0YXNldCkiKSArCiAgeWxpbSgwLCAxKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjEwLCBsYWJlbHMgPSAxOjEwKQpgYGAKCiMgU2NhdHRlciBwbG90cyBiZXR3ZWVuIGRpZmZlcmVudCBQQ3MgZm9yIHF1ZXJ5IGRhdGFzZXQgKGZyb20gcmVmZXJlbmNlIE5LIGNlbGxzIHJlbW92ZWQpCgpXZSBjcmVhdGUgc2NhdHRlciBwbG90cyB0byB2aXN1YWxpemUgdGhlIFBDQSByZXN1bHRzIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIE5LIGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGVmaW5lIGNvbG9yIHBhbGV0dGUKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbG9yX3BhbGV0dGUgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKHF1ZXJ5NCRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29sb3JfcGFsZXR0ZSkgPC0gdW5pcXVlKHF1ZXJ5NCRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKQ0QxNCBjZWxscyBhcmUgd2VsbCBzZXBhcmF0ZWQgZnJvbSB0aGUgb3RoZXIgY2VsbCB0eXBlcyBhbG9uZyB0aGUgUEMxIGF4aXMuCgpUaGVyZSBhcmUgdHdvIGRpc3RpbmN0IHBvcHVsYXRpb25zIG9mIENEOCBjZWxsczogb25lIHBvcHVsYXRpb24gaXMgc29tZXdoYXQgc2VwYXJhdGUgZnJvbSB0aGUgb3RoZXIsIGFuZCB0aGUgbGF0dGVyIHBvcHVsYXRpb24gaGFzIHNvbWUgb3ZlcmxhcCB3aXRoIENENCBjZWxscy4KCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKE5LIHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzEgdnMgUEMyLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5NCwgIlBDMSIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzIiKQpgYGAKCiMjIFBDMSB2cyBQQzMgc2NhdHRlciBwbG90CgpDRDE0IGNlbGxzIGNvbnRpbnVlIHRvIHNob3cgYSBjbGVhciBzZXBhcmF0aW9uIGZyb20gdGhlIG90aGVyIGNlbGwgdHlwZXMsIGluZGljYXRpbmcgZGlzdGluY3QgZGlmZmVyZW5jZXMgaW4gZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIG9yIG90aGVyIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMywgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTQsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoTksgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzQsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnk0LCAiUEM0IiwgIlBDMSIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDNCIpCmBgYAoKIyMgUEMyIHZzIFBDMyBzY2F0dGVyIHBsb3QKCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKE5LIHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzIgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5NCwgIlBDMyIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMyB2cyBQQzIiKQpgYGAKCiMjIFBDMyB2cyBQQzQgc2NhdHRlciBwbG90CgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMzIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTQsICJQQzMiLCAiUEM0IiwgIkNlbGxUeXBlcyIsICJQQzMgdnMgUEM0IikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKUEMxIGNhcHR1cmVzIHNpZ25pZmljYW50IHZhcmlhdGlvbiB0aGF0IGRpc3Rpbmd1aXNoZXMgQ0QxNCBjZWxscyBmcm9tIENENCBhbmQgQ0Q4IGNlbGxzLgoKYGBge3IgUEMxIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnk0LCBlY2hvPVR9CmdncGxvdChxdWVyeTQsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMxIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMiB2cyBDZWxsIHR5cGVzCgpUaGUgZm9sbG93aW5nIGFuYWx5c2lzIHJldmVhbHM6CgpDRDggQ2VsbCBQb3B1bGF0aW9uIFNwcmVhZDogVGhlIG5vdGljZWFibGUgc3ByZWFkIGluIHRoZSBDRDggY2VsbCBwb3B1bGF0aW9uIGFsb25nIFBDMiBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBzaWduaWZpY2FudCB2YXJpYWJpbGl0eSBpbiB0aGUgZ2VuZSBleHByZXNzaW9uIG9yIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3Mgb2YgQ0Q4IGNlbGxzIHRoYXQgaXMgY2FwdHVyZWQgYnkgdGhpcyBwcmluY2lwYWwgY29tcG9uZW50LiBUaGlzIHNwcmVhZCBtaWdodCBzdWdnZXN0IHRoYXQgdGhlcmUgYXJlIHN1Ymdyb3VwcyBvciBzdWJ0eXBlcyB3aXRoaW4gdGhlIENEOCBjZWxsIHBvcHVsYXRpb24gdGhhdCBleGhpYml0IGRpc3RpbmN0IHBhdHRlcm5zIGFsb25nIFBDMi4KClR3byBDRDggQ2VsbCBQb3B1bGF0aW9uczogVGhlIHByZXNlbmNlIG9mIHR3byBkaXN0aW5jdCBDRDggY2VsbCBwb3B1bGF0aW9ucyBpbiB0aGUgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QgYWxpZ25zIHdpdGggdGhlIHNwcmVhZCBzZWVuIGluIHRoZSBib3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcy4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSB2YXJpYXRpb24gY2FwdHVyZWQgYnkgUEMyIGNvbnRyaWJ1dGVzIHRvIHRoZSBkaWZmZXJlbnRpYXRpb24gYmV0d2VlbiB0aGVzZSB0d28gQ0Q4IGNlbGwgcG9wdWxhdGlvbnMuIFRoZSBzcHJlYWQgc2VlbiBpbiB0aGUgYm94cGxvdHMgbWlnaHQgYmUgYXR0cmlidXRlZCB0byB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGVzZSBwb3B1bGF0aW9ucyBpbiB0ZXJtcyBvZiB0aGUgY2FwdHVyZWQgdmFyaWF0aW9uIGFsb25nIFBDMi4KCmBgYHtyIFBDMiB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5NCwgZWNobz1UfQpnZ3Bsb3QocXVlcnk0LCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMiwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMiIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzMgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMzIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnk0LCBlY2hvPVR9CmdncGxvdChxdWVyeTQsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMzLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMzIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMgRGlzdGFuY2UgYW5hbHlzaXMgYmV0d2VlbiBkaXN0aW5jdCBjZWxsIHR5cGVzIG9mIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldAoKTm90ZTogRGlzdGFuY2VzIGFyZSBiZWluZyBjYWxjdWxhdGVkIGZvciBjZWxsIHR5cGVzIGluIG9yaWdpbmFsL29ic2VydmVkIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldC4KCklkZW50aWZpZWQgbWFya2VyIGdlbmVzIHVzaW5nIHRyYWluU2luZ2xlUigpIGZ1bmN0aW9uIGZyb20gU2luZ2xlUiBwYWNrYWdlIGFuZCB1c2VkIHRoZXNlIGdlbmVzIHRvIGNvbXB1dGUgCmRpc3RhbmNlcyBiZXR3ZWVuIGNlbGxzIGluIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldC4KCmBgYHtyIFNpbmdsZVIgZ2VuZXMsIGVjaG89Riwgd2FybmluZz1GfQojIyBUcmFpbiBTaW5nbGVSIGNsYXNzaWZpZXIgdG8gZ2V0IGxpc3Qgb2YgZ2VuZXMKdHJhaW4gPC0gdHJhaW5TaW5nbGVSKAogIHJlZmVyZW5jZSwKICByZWZlcmVuY2UkbGFiZWwpCgptYXJrZXJzIDwtIHRyYWluJG1hcmtlcnMkdW5pcXVlCgojIEV4dHJhY3QgbGFiZWxzIGZyb20gZWFjaCBlbGVtZW50IGluIHRoZSAndGFiJyBsaXN0IHVzaW5nIGxhcHBseQpsYWJlbF9saXN0cyA8LSBsYXBwbHkodGFiLCBmdW5jdGlvbih4KSB4JGFubm90YXRpb25zJGxhYmVscykKYW5ub3RhdGlvbnMgPC0gZG8uY2FsbChkYXRhLmZyYW1lLCBsYWJlbF9saXN0cykKY29sbmFtZXMoYW5ub3RhdGlvbnMpIDwtIGMoImxhYmVsc19DRDRfcmVtb3ZlZCIsICJsYWJlbHNfQ0QxNF9yZW1vdmVkIiwgImxhYmVsc19DRDhfcmVtb3ZlZCIsICJsYWJlbHNfTktfcmVtb3ZlZCIpCgojIEFkZCBhbm5vdGF0aW9ucyB0byBxdWVyeSBkYXRhc2V0CmNvbERhdGEocXVlcnkpWyxjKCJsYWJlbHNfQ0Q0X3JlbW92ZWQiLCAibGFiZWxzX0NEMTRfcmVtb3ZlZCIsICJsYWJlbHNfQ0Q4X3JlbW92ZWQiLCAibGFiZWxzX05LX3JlbW92ZWQiKV0gPC0gYW5ub3RhdGlvbnMKCiMgU3Vic2V0IHF1ZXJ5IGFuZCByZWZlcmVuY2UgZGF0YXNldCBiYXNlZCBvbiBtYXJrZXJzCnF1ZXJ5X3N1YnNldCA8LSBxdWVyeVttYXJrZXJzLCBdCnJlZmVyZW5jZV9zdWJzZXQgPC0gcmVmZXJlbmNlW21hcmtlcnMsIF0KYGBgCgojIyBEaXN0YW5jZSBiZXR3ZWVuIENENCBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBDRDQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDQiLCAiQ0Q0IiwgImV1Y2xpZGVhbiIpCmBgYAoKIyMgRGlzdGFuY2UgYmV0d2VlbiBDRDE0IGNlbGxzIGluIHJlZmVyZW5jZSBhbmQgcXVlcnkKCmBgYHtyIENEMTQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDE0IiwgIkNEMTQiLCAiZXVjbGlkZWFuIikKYGBgCgojIyBEaXN0YW5jZSBiZXR3ZWVuIENEOCBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBDRDggZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDgiLCAiQ0Q4IiwgImV1Y2xpZGVhbiIpCmBgYAoKIyMgRGlzdGFuY2UgYmV0d2VlbiBOSyBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBOSyBnZW5lcywgZWNobz1UfQpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5KHF1ZXJ5X3N1YnNldCwgcmVmZXJlbmNlX3N1YnNldCwgImxhYmVsIiwgImxhYmVsIiwgIk5LIiwgIk5LIiwgImV1Y2xpZGVhbiIpCmBgYAoKIyBEaXN0YW5jZSBhbmFseXNpcyBiZXR3ZWVuIGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBhbmQgYXNzaWduZWQgY2VsbCB0eXBlIGluIHF1ZXJ5IGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgY2FsY3VsYXRlIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgcmVtb3ZlZCBjZWxsIHR5cGVzIGluIHRoZSByZWZlcmVuY2UgYW5kIHRoZWlyIGFzc2lnbmVkIGNlbGwgdHlwZXMgaW4gdGhlIHF1ZXJ5LgoKYGBge3IgZGF0YSBwcm9jZXNzaW5nIGZvciBkaXN0YW5jZSBhbmFsc3lpcywgZWNobz1UfQojIEV4dHJhY3QgbGFiZWxzIGZyb20gZWFjaCBlbGVtZW50IGluIHRoZSAndGFiJyBsaXN0IHVzaW5nIGxhcHBseQpsYWJlbF9saXN0cyA8LSBsYXBwbHkodGFiLCBmdW5jdGlvbih4KSB4JGFubm90YXRpb25zJGxhYmVscykKYW5ub3RhdGlvbnMgPC0gZG8uY2FsbChkYXRhLmZyYW1lLCBsYWJlbF9saXN0cykKY29sbmFtZXMoYW5ub3RhdGlvbnMpIDwtIGMoImxhYmVsc19DRDRfcmVtb3ZlZCIsICJsYWJlbHNfQ0QxNF9yZW1vdmVkIiwgImxhYmVsc19DRDhfcmVtb3ZlZCIsICJsYWJlbHNfTktfcmVtb3ZlZCIpCmBgYAoKIyMgRGlzdGFuY2UgY29tcHV0YXRpb24gYmV0d2VlbiBDRDQgY2VsbHMgaW4gcXVlcnkgYW5kIENEOCBjZWxscyBpbiByZWZlcmVuY2UKCldoZW4sIENEOCBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENENCBpbiBxdWVyeS4KCmBgYHtyIENEOCB2cyBDRDQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbHNfQ0Q0X3JlbW92ZWQiLCAibGFiZWwiLCAiQ0Q4IiwgIkNENCIsICJldWNsaWRlYW4iKQpgYGAKCiMjIERpc3RhbmNlIGNvbXB1dGF0aW9uIGJldHdlZW4gQ0Q4IGNlbGxzIGluIHF1ZXJ5IGFuZCBDRDE0IGNlbGxzIGluIHJlZmVyZW5jZQoKV2hlbiwgQ0QxNCBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENEOCBpbiBxdWVyeS4KCmBgYHtyIENEMTQgdnMgQ0Q0IGdlbmVzLCBlY2hvPVR9CmNhbGN1bGF0ZVBhaXJ3aXNlRGlzdGFuY2VzQW5kUGxvdERlbnNpdHkocXVlcnlfc3Vic2V0LCByZWZlcmVuY2Vfc3Vic2V0LCAibGFiZWxzX0NEMTRfcmVtb3ZlZCIsICJsYWJlbCIsICJDRDgiLCAiQ0QxNCIsICJldWNsaWRlYW4iKQpgYGAKCiMjIERpc3RhbmNlIGNvbXB1dGF0aW9uIGJldHdlZW4gQ0Q0IGNlbGxzIGluIHF1ZXJ5IGFuZCBDRDggY2VsbHMgaW4gcmVmZXJlbmNlCgpXaGVuLCBDRDggY2VsbHMgd2VyZSByZW1vdmVkIGZyb20gdGhlIHJlZmVyZW5jZSBhbmQgd2hlbiB0aGlzIHJlZmVyZW5jZSB3YXMgdXNlZCB0byBhbm5vdGF0ZSB0aGUgcXVlcnkgZGF0YXNldCwgdGhlc2UgY2VsbHMgd2VyZSBhc3NpZ25lZCBhcyBDRDQgaW4gcXVlcnkuCgpgYGB7ciBDRDQgdnMgQ0Q4IGdlbmVzLCBlY2hvPVR9CmNhbGN1bGF0ZVBhaXJ3aXNlRGlzdGFuY2VzQW5kUGxvdERlbnNpdHkocXVlcnlfc3Vic2V0LCByZWZlcmVuY2Vfc3Vic2V0LCAibGFiZWxzX0NEOF9yZW1vdmVkIiwgImxhYmVsIiwgIkNENCIsICJDRDgiLCAiZXVjbGlkZWFuIikKYGBgCgojIyBEaXN0YW5jZSBjb21wdXRhdGlvbiBiZXR3ZWVuIENEOCBjZWxscyBpbiBxdWVyeSBhbmQgTksgY2VsbHMgaW4gcmVmZXJlbmNlCgpXaGVuLCBOSyBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENEOCBpbiBxdWVyeS4KCmBgYHtyIENEOCB2cyBOSyBnZW5lcywgZWNobz1UfQpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5KHF1ZXJ5X3N1YnNldCwgcmVmZXJlbmNlX3N1YnNldCwgImxhYmVsc19OS19yZW1vdmVkIiwgImxhYmVsIiwgIkNEOCIsICJOSyIsICJldWNsaWRlYW4iKQpgYGAKCiMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKSBLZXkgT2JzZXJ2YXRpb25zOgoKQ0Q0IGFuZCBDRDggT3ZlcmxhcCBpbiBQQzEgdnMgUEMyIGluIHRoZSBRdWVyeToKVGhlIG92ZXJsYXAgb2JzZXJ2ZWQgYmV0d2VlbiBDRDQgYW5kIENEOCBjZWxscyBpbiB0aGUgUEMxIHZzIFBDMiBwbG90IG9mIHRoZSBxdWVyeSBkYXRhc2V0IHN1Z2dlc3RzIHRoZSBwcmVzZW5jZSBvZiBzaGFyZWQgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIGJldHdlZW4gdGhlc2UgdHdvIGNlbGwgdHlwZXMuIFRoaXMgc2hhcmVkIHBhdHRlcm4gbWlnaHQgbGVhZCB0byB0aGVpciBwcm94aW1pdHkgaW4gdGhlIFBDQSBzcGFjZS4KCkNEMTQsIENEOCwgYW5kIE5LIFNlcGFyYXRpb24gaW4gUEMxIHZzIFBDMiBBZnRlciBDRDQgUmVtb3ZhbDoKVXBvbiByZW1vdmluZyBDRDQgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQsIHRoZXJlIGlzIGFuIGltcHJvdmVkIHNlcGFyYXRpb24gb2YgQ0QxNCwgQ0Q4LCBhbmQgTksgY2VsbHMgaW4gdGhlIFBDMSB2cyBQQzIgcGxvdC4gVGhpcyBlbmhhbmNlbWVudCBpbiBzZXBhcmF0aW9uIGNvdWxkIGJlIGF0dHJpYnV0ZWQgdG8gdGhlIHJlZHVjdGlvbiBvZiBub2lzZSBjYXVzZWQgYnkgQ0Q0IGNlbGxzLCBlbmFibGluZyBhIGNsZWFyZXIgZGlzdGluY3Rpb24gYmV0d2VlbiB0aGVzZSBjZWxsIHBvcHVsYXRpb25zLgoKVHdvIENEOCBQb3B1bGF0aW9ucyBpbiBQQzIgdnMgUEMzIEFmdGVyIENENCBSZW1vdmFsOgpUaGUgYWJzZW5jZSBvZiBDRDQgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIHVuY292ZXJlZCBwcmV2aW91c2x5IG1hc2tlZCBoZXRlcm9nZW5laXR5IHdpdGhpbiBDRDggY2VsbHMuIFRoaXMgaXMgZXZpZGVudCBmcm9tIHRoZSBlbWVyZ2VuY2Ugb2YgdHdvIGRpc3RpbmN0IENEOCBzdWJwb3B1bGF0aW9ucyBpbiB0aGUgUEMyIHZzIFBDMyBwbG90LCBpbmRpY2F0aW5nIHRoYXQgQ0Q0IGNlbGxzIHdlcmUgaW5mbHVlbmNpbmcgdGhlIGdyb3VwaW5nIG9mIENEOCBjZWxscy4KClR3byBDRDggUG9wdWxhdGlvbnMgaW4gUEMxIHZzIFBDMiBBZnRlciBDRDE0IFJlbW92YWw6CkZvbGxvd2luZyB0aGUgcmVtb3ZhbCBvZiBDRDE0LCB0aGVyZSBhcmUgbm90YWJsZSBjaGFuZ2VzIGluIHRoZSB2YXJpYW5jZSBjYXB0dXJlZCBieSBQQzEgYW5kIFBDMi4gVGhpcyB1bm1hc2tpbmcgb2YgdmFyaWFiaWxpdHkgaGFzIGxlZCB0byB0aGUgaWRlbnRpZmljYXRpb24gb2YgdHdvIGRpc3RpbmN0IENEOCBzdWJwb3B1bGF0aW9ucyBpbiB0aGUgUEMxIHZzIFBDMiBwbG90LCBzdWdnZXN0aW5nIHRoYXQgQ0QxNCBjZWxscyB3ZXJlIG1hc2tpbmcgdGhpcyBoZXRlcm9nZW5laXR5LgoKVHdvIENENCBQb3B1bGF0aW9ucyBpbiBQQzIgdnMgUEMzIEFmdGVyIENEOCBSZW1vdmFsOgpUaGUgYWJzZW5jZSBvZiBDRDggVCBjZWxscyBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIHJldmVhbGVkIGhpZGRlbiB2YXJpYWJpbGl0eSB3aXRoaW4gQ0Q0IFQgY2VsbHMuIFRoaXMgaXMgZXZpZGVudCBmcm9tIHRoZSBhcHBlYXJhbmNlIG9mIHR3byBkaXN0aW5jdCBDRDQgc3VicG9wdWxhdGlvbnMgaW4gdGhlIFBDMiB2cyBQQzMgcGxvdCwgaGlnaGxpZ2h0aW5nIHRoYXQgdGhlIHByZXNlbmNlIG9mIENEOCBjZWxscyB3YXMgaW1wYWN0aW5nIHRoZSByZXByZXNlbnRhdGlvbiBvZiBDRDQgY2VsbHMuCgpUd28gQ0Q4IFBvcHVsYXRpb25zIGluIFBDMSB2cyBQQzIgQWZ0ZXIgTksgUmVtb3ZhbDoKUmVtb3ZpbmcgTksgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGhhZCBhbiBpbmZsdWVuY2Ugb24gdGhlIHBvc2l0aW9uaW5nIG9mIENEOCBUIGNlbGxzIGluIHRoZSBQQ0Egc3BhY2UuIFRoaXMgZWZmZWN0IGlzIHNlZW4gaW4gdGhlIGVtZXJnZW5jZSBvZiB0d28gQ0Q4IGNlbGwgcG9wdWxhdGlvbnMgaW4gdGhlIFBDMSB2cyBQQzIgcGxvdCwgaW5kaWNhdGluZyB0aGF0IHRoZSBwcmVzZW5jZSBvZiBOSyBjZWxscyB3YXMgYWZmZWN0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgQ0Q4IGNlbGxzLgoKRGlzdGluY3QgQ0Q0LCBDRDE0LCBhbmQgQ0Q4IFBvcHVsYXRpb25zIGluIFBDMSB2cyBQQzMgQWZ0ZXIgTksgUmVtb3ZhbDoKVGhlIHJlbW92YWwgb2YgTksgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGJyb3VnaHQgYWJvdXQgY2xlYXJlciBzZXBhcmF0aW9uIGJldHdlZW4gQ0Q0IFQgY2VsbHMsIENEMTQsIGFuZCBDRDggY2VsbHMgaW4gdGhlIFBDMSB2cyBQQzMgcGxvdC4gVGhlIG1hc2tpbmcgZWZmZWN0IG9mIE5LIGNlbGxzIG9uIHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZXNlIHBvcHVsYXRpb25zIGhhcyBiZWVuIGFsbGV2aWF0ZWQuCgpUd28gQ0Q4IFBvcHVsYXRpb25zIGluIFBDMiB2cyBQQzMgQWZ0ZXIgQ0Q0IFJlbW92YWw6ClRoZSBhYnNlbmNlIG9mIENENCBjZWxscyBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBzdWJ0bGUgaGV0ZXJvZ2VuZWl0eSB3aXRoaW4gQ0Q4IGluIHRoZSBQQzIgdnMgUEMzIHBsb3QuIFRoaXMgZmluZGluZyB1bmRlcnNjb3JlcyBob3cgdGhlIHByZXNlbmNlIG9mIENENCBjZWxscyB3YXMgaW1wYWN0aW5nIHRoZSByZXByZXNlbnRhdGlvbiBvZiBDRDggY2VsbCB2YXJpYWJpbGl0eS4KCg==